﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#pragma once

#include "ui_GridGroupMainDlg.h"
#include "ui_OrthogonalGridGroupWidget.h"
#include "ui_RadialGridGroupWidget.h"
#include "GridGroupNewParam.h"
#include "NumberValidator.h"
#include "LineEditValidateHelper.h"
#include <set>
#include "OwnerPtr.h"
#include <QDialog>
#include <QItemDelegate>

namespace gcmp
{
    class GridGroupNewDlg : public QDialog
    {
        Q_OBJECT

    public:
        GridGroupNewDlg(QWidget *pParent);
        //获取正交轴网Tab页用于生成轴网的数据
        OrthogonalGridGroupParam GetOrthogonalGridGroupData() const;
        //获取辐射轴网Tab页用于生成轴网的数据
        RadialGridGroupParam GetRadialGridGroupData() const;
        //获取当前Tab页的轴网类型
        EnGridGroupType GetGridGroupType() const;
        //获取整个对话框各个控件的配置数据
        GridGroupDlgConfigParam GetConfigData() const;
        //根据外部的配置数据恢复对话框界面
        bool SetConfigData(const GridGroupDlgConfigParam& configParam);


    private slots:
        void OnOKButtonClick();
        void OnCancelButtonClick();
        void OnCurrentIndexChanged(int index);
        void OnAnchorTypeComboBoxChanged();
        void OnCheckBoxChecked();
        void OnLineEditValidStateUpdated(bool valid);
        void onMoveRequested(const QPoint& cursorPos, const QPoint& offset);
    private:
        GridGroupDlgConfigParam::OrthogonalGridGroupDlgConfigParam GetOrthogGridGroupCommonParam() const;
        GridGroupDlgConfigParam::RadialGridGroupDlgConfigParam GetRadialGridGroupCommonParam() const;
        void CollectAnchorPosType();
        void CollectIsRotate();

    private:
        EnOrthogonalGridGroupAnchorPositionType m_orthoAnchorPosType;
        EnRadialGridGroupAnchorPositionType m_radialAnchorPosType;
        bool m_orthoGridGroupIsRotate;
        bool m_radialGridGroupIsRotate;
        Ui::GridGroupNew m_ui;
    };

    class LineEditDelegate: public QItemDelegate
    {
        Q_OBJECT
    public:
        explicit LineEditDelegate(QObject *parent = 0);
        QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
        void setEditorData(QWidget *editor, const QModelIndex &index) const;
        void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
    protected slots:
        void OnValidStateUpdated(QLineEdit* pEdit, bool valid);
    protected:
        bool m_isValid; 
        //记录上次输入的有效值，若此次输入不合法则显示此值
        mutable QString m_lastValidData; 
        //输入数据合法性验证助手
        mutable OwnerPtr<gcmp::LineEditValidateHelper> m_opValidateHelper;
        mutable std::unordered_map<const QLineEdit*, const ValidatorBase*> m_validators;
        //以关联了Validator的LineEdit作为编辑器
        mutable OwnerPtr<QLineEdit> m_tableWidgetLineEdit;
        //正整数验证器
        NumberValidator<int> m_lenValidator;
    };

    class RadialTableWidgetLineEditDelegate :public LineEditDelegate
    {
        Q_OBJECT
    public:
        explicit RadialTableWidgetLineEditDelegate(QObject *parent = 0);
        QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    private:
        //浮点数验证器
        NumberValidator<double> m_angleValidator;
    };

    class CommonGridGroupWidget :public QWidget
    {

        Q_OBJECT
    public:
        friend class LineEditDelegate;

        typedef std::vector<std::pair<std::wstring, double>> AxisPositionSet;

        CommonGridGroupWidget(QWidget *pParent);
        virtual ~CommonGridGroupWidget() {};
        
        void StartDataCollection();

        //初始化正交、辐射轴网界面
        virtual bool InitialConfig(const GridGroupDlgConfigParam& initParam) = 0;

        virtual bool Validate();

        //获取两组轴网定位数据
        AxisPositionSet GetLeftAxisData() const;
        AxisPositionSet GetRightAxisData() const;

        //获取左右两TableWidget的配置数据
        GridGroupDlgConfigParam::GridGroupDlgConfigCommonParam GetLeftTableIndex() const;
        GridGroupDlgConfigParam::GridGroupDlgConfigCommonParam GetRightTableIndex() const;


    signals:
        void tableWidgetLineChanged(QTableWidget *pQTableWidget);
        void lineEditValidStateUpdated(bool valid);

    protected slots :
        void OnAddUpLeftAxis();
        void OnAddDownLeftAxis();
        void OnDeleteLeftAxis();
        void OnAddUpRightAxis();
        void OnAddDownRightAxis();
        void OnDeleteRightAxis();
        void OnLeftTableMultiLineClicked();
        void OnRightTableMultiLineClicked();
        virtual void OnLeftGridNameBoxChanged(int index);
        virtual void OnRightGridNameBoxChanged(int index);
        void EnableDelLineBtn(QTableWidget *currTableWidget);
        void OnValidStateUpdated(QLineEdit* pEdit, bool valid);

    protected:

        enum EnLineAddType
        {
            GT_AddUp = 0,
            GT_AddDown
        };

        enum EnGridNameDuplicatedType
        {
            GT_DuplicatedWithDoc = 0,
            GT_DuplicatedWithSet,
            GT_NoDuplicatd
        };

        //向表格中添加数据
        int AddAxis(QTableWidget *pTableWidget, QLineEdit *pQLineEdit, EnLineAddType pLineAddType);

        //初始化正交、辐射轴网Tab页设置（设置默认选中行，表格选择模式，连接信号槽以及日志支持）
        void InitWidgetSettings();

        //删除表格中数据
        int DeleteAxis(QTableWidget *currTableWidget);

        //从表格中摘取数据到轴网定位数据中
        void CollectDataFromTable(QTableWidget *pTableWidget, AxisPositionSet& axises);

        virtual void LeftGridNameBoxChanged(QComboBox* pNameComboBox,int index);
        virtual void RightGridNameBoxChanged(QComboBox* pNameComboBox,int index);

        //根据前、后缀组合轴号
        std::wstring ComposeName(QTableWidget *pTableWidget, const std::wstring &currName) const;

        //生成与项目中已有轴号不重名的轴号
        std::wstring GetNoDuplicatedName(const std::wstring& currName) const;

        //根据轴网定位数据恢复TableWidget中显示的数据
        bool InitLeftAndRightTableWidgets(const std::vector<std::pair<std::wstring, std::wstring>> &leftAxisSet, const std::vector<std::pair<std::wstring, std::wstring>> &rightAxisSet);
        bool InitTableWidget(QTableWidget* pTableWidget, const std::vector<std::pair<std::wstring, std::wstring>> &axisSet);

        virtual void InitValidators();

        //验证轴网轴号的有效性，若与项目文档中已有轴号重名，则添加后缀重新生成
        bool ValidateAndRectifyGridName();

        //验证轴网横、纵（径向、环向）定位数据有效性
        virtual bool ValidateDataCollected(const AxisPositionSet &axisSet) const;

        //轴网定位数据
        AxisPositionSet m_leftAxis;
        AxisPositionSet m_rightAxis;

        //输入数据合法性验证助手
        OwnerPtr<gcmp::LineEditValidateHelper> m_opValidateHelper;
        std::unordered_map<const QLineEdit*, const ValidatorBase*> m_validators;
        NumberValidator<int> m_lenValidator; //轴间距验证器
        OwnerPtr<LineEditDelegate> m_tableWidgetDelegate;

        //公共界面控件
        QPushButton *m_pushButton_AddLineUp_Left;
        QPushButton *m_pushButton_AddLineDown_Left;
        QComboBox *m_comboBox_GridName_Left;
        QLineEdit *m_lineEdit_ExGridName_Left;
        QComboBox *m_comboBox_ExGridName_Left;
        QTableWidget *m_tableWidget_Left;
        QComboBox *m_comboBox_GridType_Left;
        QLineEdit *m_lineEdit_InputValue_Left;
        QPushButton *m_pushButton_DelLine_Left;
        QPushButton *m_pushButton_AddLineUp_Right;
        QPushButton *m_pushButton_AddLineDown_Right;
        QComboBox *m_comboBox_GridName_Right;
        QLineEdit *m_lineEdit_ExGridName_Right;
        QComboBox *m_comboBox_ExGridName_Right;
        QTableWidget *m_tableWidget_Right;
        QComboBox *m_comboBox_GridType_Right;
        QLineEdit *m_lineEdit_InputValue_Right;
        QPushButton *m_pushButton_DelLine_Right;

        //上一次输入的有效值，若输入不合法则显示此值
        bool m_isLeftInputValid;
        bool m_isRightInputValid;
        bool m_isRadiusInputValid;
        QString m_leftInputValue;
        QString m_rightInputValue;
        int m_rowIndexForJournal;

    private:

        //记录每次选择集中的最后一行行号，若点击空白处使Table中选择集为空则强制选中这一行
        int m_leftTableFinalLineClicked;
        int m_rightTableFinalLineClicked;

    };

    class OrthogonalGridGroupWidget :public CommonGridGroupWidget
    {
        Q_OBJECT
    public:
        OrthogonalGridGroupWidget(QWidget *pParent);

        virtual bool InitialConfig(const GridGroupDlgConfigParam& initParam) override;

    private:
        Ui::tab_Orthogonal m_orthoTab;
    };

    class RadialGridGroupWidget :public CommonGridGroupWidget
    {
        Q_OBJECT
    public:
        RadialGridGroupWidget(QWidget *pParent);

        virtual bool InitialConfig(const GridGroupDlgConfigParam& initParam) override;
        virtual bool Validate() override;
        double GetInnerRadius() const { return m_isRadiusInputValid?m_radialTab.lineEdit_InnerRadius->text().toDouble():m_innerRadiusValue; };

    protected:
        virtual void InitValidators() override;
        virtual bool ValidateDataCollected(const AxisPositionSet &axisSet) const override;

    protected slots:
        virtual void OnLeftGridNameBoxChanged(int index) override;
        virtual void OnRightGridNameBoxChanged(int index) override;

    private:
        Ui::tab_Radiation m_radialTab;
        OwnerPtr<RadialTableWidgetLineEditDelegate> m_angleDelegate;
        //轴间角验证器
        NumberValidator<double> m_angleValidator;
        //保存上一次内弧半径有效值
        double m_innerRadiusValue;
    };
}





